package com.example.common.util.easyexcel;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.WriteDirectionEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Objects;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.Assert;

/**
 * easyexcel写工具类
 *
 * @author zjarlin
 * @since 2023/04/30
 */
@Slf4j
public class EasyExcelWriteUtil {
    /**
     * 模板填充
     *
     * @param response     响应
     * @param vo           签证官
     * @param templatePath 模板路径
     * @param fileName     文件名称 入参
     * @author addzero
     * @since 2022/11/27
     */
    @SneakyThrows(Exception.class)
    public static <VO> void templateFill(@NonNull HttpServletResponse response, VO vo, String templatePath, @NonNull String fileName) {
        templateFill(response, vo, null, templatePath, fileName);
    }

    /**
     * 模板填充
     *
     * @param response     响应
     * @param vo           一维字段填充
     * @param dtos         dto 二维列表填充
     * @param templatePath 模板路径
     * @param fileName     文件名称 入参
     * @author addzero
     * @since 2022/11/27
     */
    @SneakyThrows(Exception.class)
    public static <VO, DTO> void templateFill(HttpServletResponse response, VO vo, List<DTO> dtos, String templatePath, @NonNull String fileName) {

        ServletOutputStream out = response.getOutputStream();
        response.setContentType("multipart/form-data");
        response.setCharacterEncoding("UTF-8");

        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        //文件模板输入流
        InputStream inputStream = new ClassPathResource(templatePath).getInputStream();

        ExcelWriter writer = EasyExcel.write(out)
            .withTemplate(inputStream)
            //.registerConverter(new LocalDateConverter())
            //.registerConverter(new LocalDateTimeConverter())
            .build();

        //3.4 设置强制计算公式：不然公式会以字符串的形式显示在excel中
        Workbook workbook = writer.writeContext().writeWorkbookHolder().getWorkbook();
        workbook.setForceFormulaRecalculation(true);

        WriteSheet sheet = EasyExcel.writerSheet(0).build();
        //填充列表开启自动换行,自动换行表示每次写入一条list数据是都会重新生成一行空行,此选项默认是关闭的,需要提前设置为true
        FillConfig fillConfig = FillConfig.builder()
            .forceNewRow(true)
            .direction(WriteDirectionEnum.VERTICAL)
            .build();
        //填充一维数据
        writer.fill(vo, sheet);
        //填充二维数据
        if (CollUtil.isNotEmpty(dtos)) {
            writer.fill(dtos, fillConfig, sheet);
        }
        //填充完成
        writer.finish();
        out.flush();
    }

    /**
     * 列表导出下载
     *
     * @param response 响应
     * @param list     列表
     * @param fileName 文件名称 入参
     * @author addzero
     * @since 2022/11/27
     */
    @SneakyThrows(IOException.class)
    public static <T> void listExport(HttpServletResponse response, List<T> list, @NonNull String fileName) {

        Objects.requireNonNull(list, "export list must not be null");
        Assert.notEmpty(list, "无数据");
        //easyExcel底层单sheet限制2万条
        Assert.isTrue(list.size() < 20_000, "导出只支持2万条以内数据,请细化筛选条件");

        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        response.setHeader("content-disposition", "attachment; filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
        final Class<?> aClass = list.get(0).getClass();
        EasyExcel.write(response.getOutputStream(), aClass)
            //自动设列宽
            //.registerWriteHandler(new ExcelWidthStyleStrategy())
            //自动设行高
            //.registerWriteHandler(new ExcelHeightStyleStrategy())
            .sheet("sheet1").doWrite(list);

    }

}
